package com.liik.game;


import java.util.Stack;

import com.liik.game.mvc.GameController;
import com.liik.game.mvc.GameModel;
import com.liik.game.mvc.GameRenderer;
import com.liik.game.mvc.object.Display;
import com.liik.game.mvc.object.Navigation;
import com.liik.game.mvc.object.Menu.Item;
import com.liik.game.mvc.tiled.TiledGameModel;
import com.liik.game.mvc.tiled.object.Entity;
import com.liik.game.util.Vector;

import android.content.Context;
import android.graphics.Canvas;
import android.os.Bundle;

public class ScreenHolder {
	
	private Stack<Integer> screens;
	private GameModel[] gameModels;
	private GameController[] gameControllers;
	private GameRenderer[] gameRenderers;
	private int nextFreeSlot;
	private GameModel activeModel;
	private GameController activeController;
	private GameRenderer activeRenderer;
	
	public ScreenHolder(int maxModels) {
		screens = new Stack<Integer>();
		gameModels = new GameModel[maxModels];
		gameControllers = new GameController[maxModels];
		gameRenderers = new GameRenderer[maxModels];
		nextFreeSlot = 0;
		activeModel = null;
		activeController = null;
		activeRenderer = null;
	}
	
	public int addGameModel(int screenId, GameModel gameModel, GameController gameController, GameRenderer gameRenderer) {
		if (screenId != nextFreeSlot) {
			throw new IllegalArgumentException("Invalid screen ID!");
		}
		if (nextFreeSlot < gameModels.length) {
			gameModels[nextFreeSlot] = gameModel;
			gameControllers[nextFreeSlot] = gameController;
			gameRenderers[nextFreeSlot] = gameRenderer;
			gameController.setScreenHolder(this);
			return nextFreeSlot++;
		}
		throw new RuntimeException("Too many screens!");
	}
	
	public void pushScreen(int screenID, Object message) {
		if (screenID < 0 || screenID >= gameModels.length || gameModels[screenID] == null) {
			throw new IllegalArgumentException("Tried to select an invalid screen: " + screenID);
		}
		screens.push(screenID);
		activeModel = gameModels[screenID];
		activeController = gameControllers[screenID];
		activeRenderer = gameRenderers[screenID];
		activeController.controlGained(message, activeModel, activeRenderer);
		System.gc();
	}
	
	public void popScreen(Object message) {
		screens.pop();
		if (screens.isEmpty()) {
			exit();
		}		
		int screenID = screens.peek();
		activeModel = gameModels[screenID];
		activeController = gameControllers[screenID];
		activeRenderer = gameRenderers[screenID];
		activeController.controlGained(message, activeModel, activeRenderer);
		System.gc();
	}

	private void exit() {
		System.exit(0);
	}

	public void render(Navigation navigation, Display display, Canvas canvas) {
		activeRenderer.render(activeModel, navigation, display, canvas); 
	}

	private Vector scrollHelper = new Vector();
	
	public void update(Navigation navigation, Display display) {
		GameModel activeGameModel = activeModel;
		activeController.update(activeGameModel, navigation, display);
		if (activeGameModel instanceof TiledGameModel) {
			TiledGameModel tgm = (TiledGameModel) activeGameModel;
			scrollHelper.set(tgm.getPointOfInterest());
			if (scrollHelper.x < display.dimensions.x / 2)
				scrollHelper.x = display.dimensions.x / 2;
			else if (scrollHelper.x > tgm.getWidth() - display.dimensions.x / 2)
				scrollHelper.x = tgm.getWidth() - display.dimensions.x / 2;
			if (scrollHelper.y < display.dimensions.y / 2)
				scrollHelper.y = display.dimensions.y / 2;
			else if (scrollHelper.y > tgm.getHeight() - display.dimensions.y / 2)
				scrollHelper.y = tgm.getHeight() - display.dimensions.y / 2;
			display.scrollTo(scrollHelper);
		}
	}

	public boolean handleMenuEvent(float x, float y) {
		Item menuItem = activeModel.getMenu().getItem(x, y);
		if (menuItem != null) {
			activeController.handleMenuEvent(menuItem, activeModel);
			return true;
		}
		return false;
	}

	public void handleDefaultAction(float x, float y) {
		if (activeModel instanceof TiledGameModel) {
			TiledGameModel tiledGameModel = (TiledGameModel) activeModel;
			Entity entityFromPoint = tiledGameModel.getEntityFromPoint(x, y);
			if (entityFromPoint != null) {
				entityFromPoint.handleDefaultAction(tiledGameModel, System.currentTimeMillis());
			}
		}
	}

	public void onDestroy() {
		// TODO Auto-generated method stub
		
	}

	public void onStop() {
		// TODO Auto-generated method stub
		
	}

	public void onPause() {
		// TODO Auto-generated method stub
		
	}

	public void onResume() {
		// TODO Auto-generated method stub
		
	}

	public void resetState() {
		// TODO Auto-generated method stub
		
	}

	public void restoreState(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		
	}

	public void saveState(Bundle outState) {
		// TODO Auto-generated method stub
		
	}

	public void setContext(Context context) {
		for (int i = 0; i < gameRenderers.length; ++i) {
			if (gameRenderers[i] != null) {
				gameRenderers[i].setContext(context);
			}
		}
	}
}
